#pragma once
#include <iostream>
#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include <cerrno>
#include <cstring>
#include <cassert>
#include <cstdlib>
#include <netinet/in.h>
#include <strings.h>
#include <arpa/inet.h>
#include <functional>
enum{SOCK_ERR = 1, BIND_ERR, USAGE_ERR, FILE_ERR};
namespace Server
{
    using namespace std;
    static const string defaultIp = "0.0.0.0";

    
    class udpServer
    {
        using func_t = function<void(int, string, uint16_t, string)>;
    public:
        udpServer(func_t callBack, const uint16_t& port, const string& ip = defaultIp)
            :_port(port) ,_ip(ip) ,_sockfd(-1)  ,_callBack(callBack)
        {}
        void initServer()
        {
            // 1.创建套接字
            _sockfd = socket(AF_INET, SOCK_DGRAM, 0);
            if(_sockfd == -1)
            {
                cout << "socket error " << errno << " err string: " << strerror(errno) << endl;
                exit(SOCK_ERR);
            }
            cout << "socket create success " << endl;


            // 2.绑定ip和端口
            struct sockaddr_in local;
            bzero(&local, sizeof(local));
            local.sin_family = AF_INET;
            local.sin_port = htons(_port); //将主机的数据转成网络字节序即大端格式
            local.sin_addr.s_addr = inet_addr(_ip.c_str()); // 1.string->uint32_t 2.htonl  
            //local.sin_addr.s_addr = htonl(INADDR_ANY); INADDR_ANY 就是000000
            

            int n = bind(_sockfd, (struct sockaddr*)&local, sizeof(local));
            if(-1 == n)
            {
                cout << "bind error " << errno << " err string: " << strerror(errno) << endl;
                exit(BIND_ERR);
            }
        }
        void start()
        {
            //读取数据
            char buffer[1024];
            while(1)
            {
    
                struct sockaddr_in peer;
                socklen_t socklen = sizeof(peer);
                ssize_t n = recvfrom(_sockfd, buffer, sizeof(buffer) - 1, 0, (sockaddr*)&peer, &socklen);
                if(n > 0)
                {
                    buffer[n] = 0; 
                    string clientIp = inet_ntoa(peer.sin_addr);  // 1.网络序列 2. 十进制转点分式 
                    uint16_t clientPort = ntohs(peer.sin_port);
                    string message = buffer;
                    cout << clientIp << "[" << clientPort << "]# " << message << endl;
                    _callBack(_sockfd, clientIp, clientPort, message);
                }
                else
                {
                    cerr << "recvfrom err: " << errno << " : " << strerror(errno) << endl;
                }
            }
        }
        ~udpServer()
        {}
    private:
        uint16_t _port; //端口号
        string _ip; //ip地址
        int _sockfd; //套接字文件描述符
        func_t _callBack; //回调
    };
}